#include <iostream>
#include <vector>
#include "geometry.h"
#include "scene.h"

Color3 trace(const Ray& cam, const std::vector<Object *>& objs, const std::vector<Light>& lights)
{
	float dist = 100000.0;
	float closest = dist;
	Color3 temp_color;
	Color3 return_color;
	Vec3 intersect;

	for (size_t i = 0; i < objs.size(); i++)
	{

		if (objs[i]->intersect(cam, dist, temp_color, intersect))
		{
			if (dist < closest)
			{
				closest = dist;
				// now lets do diffuse lighting
				Vec3 normal = intersect.normal();
				Vec3 origin = objs[i]->getOrigin();

				return_color = temp_color;

				float oldLightCoef = 1.0f;
				for ( size_t l = 0; l < lights.size(); l++ )
				{
					Light light = lights[l];

					Vec3 lightDir = light.origin - intersect;
					lightDir.normalize();
					float lightCoef = lightDir.dot( normal );

					if ( lightCoef < 0.0 )
						lightCoef = 0.0f; // ambient light hack

					if ( oldLightCoef < lightCoef )
					{
						lightCoef = oldLightCoef;

					}

					return_color.x = return_color.x * lightCoef;
					return_color.y = return_color.y * lightCoef;
					return_color.z = return_color.z * lightCoef;

				}
			}

		}
	}

	return return_color;
}

int main()
{
    std::vector<Sphere> spheres;
    Sphere sph(Vec3(0.0, 200.0, 0.0), 125.0, Color3(255, 0, 0));
    Sphere sph2(Vec3(0.0, -200.0, 0.0), 125.0, Color3(255, 255, 0));
    Sphere sph3(Vec3(200.0, 0.0, 0.0), 125.0, Color3(0, 255, 0));
    Sphere sph4(Vec3(-200.0, 0.0, 0.0), 125.0, Color3(0, 0, 255));


    std::vector<Object *> objs;
    objs.push_back(&sph);
    objs.push_back(&sph2);
    objs.push_back(&sph3);
    objs.push_back(&sph4);
	//std::cout << (int)sph.color.x << std::endl;
	std::vector<Light> lights;
	lights.push_back( Vec3( 0.0, 0.0, -800.0 ) );

	/**
	 * Scene represents the virtual "screen."  It determines the area of the final image.
	 * Raster is the actual image data.  By increasing raster (and leaving scene the same)
	 * you can keep the same objects on screen, it just makes every larger.
	 * @arg width, height
	 */
	Scene scene(2000, 1000);
	// Vec3(ORIGN), Vec3(DIRECTION)
	// the Z component of the DIRECTION vector doesn't do anything
	// use scene.setFieldOfView() to set the distance of the virtual screen to the origin
	// defaults to 300
	scene.camSetup(Vec3(0.0, 0.0, 1000.0), Vec3(0.0, 0.0, 0.0));

	// setup image
	Raster raster(1000, 500);

	float height_ratio = raster.getHeight() / (float)scene.getHeight();
	float width_ratio = raster.getWidth() / (float)scene.getWidth();

    for ( int y = 0; y < raster.getHeight(); y++ )
	{
		for ( int x = 0; x < raster.getWidth(); x++)
		{

			scene.cam.direction.x = (x / width_ratio) - ( scene.getWidth() / 2.0 );
			scene.cam.direction.y = (y / height_ratio) - ( scene.getHeight() / 2.0 );
			scene.cam.direction.z = scene.cam.origin.z + scene.getFieldOfView();
			scene.cam.direction.normalize();

			Color3 color;

			color = trace(scene.cam, objs, lights);

			raster.push_color(color);

		}
    }
    raster.saveJPEG();
    return 0;
}

/*
void save_rgb_image( std::size_t w, std::size_t h, const std::vector<unsigned char> &raster )
{
	using jpegxx::raster_details;
	raster_details details(raster_details::rgb, w, h);
	unsigned seed;
	seed = (unsigned)time(NULL);
	srand(seed);
	char filename[50];
	sprintf(filename, "./images/out%d.jpg", seed);
	jpegxx::write_image(details, filename, raster.begin(), raster.end(), 1.0);
}*/
